﻿//  --------------------------------
//  Copyright (c) 2010 Michael Schuler, Sascha Burger. All rights reserved.
//  This source code is made available under the terms of the Microsoft Public License (Ms-PL)
//  http://p2pmessaging.codeplex.com/license
//  ---------------------------------
using System.IO;
using System.Security.Cryptography;
using p2pMessaging.Interfaces;

namespace p2pMessaging.BL
{
	/// <summary>
	/// Service to provide basic encrypting and decrypting.
	/// </summary>
	public sealed class CryptographyService : ICryptographyService
	{
		private static readonly byte[] mySalt = new byte[]
		{
			176, 47, 226, 153, 214, 25, 183, 97,
			146, 111, 181, 214, 120, 119, 20, 127
		};
		
		/// <summary>
		/// Encrypt a plain byte array into cipher byte array.
		/// </summary>
		/// <param name="plain">plain byte array</param>
		/// <param name="algorithm">algorithm to encrypt</param>
		/// <param name="password">password to encrypt</param>
		/// <returns>cipher byte array</returns>
		public byte[] Encrypt(byte[] plain, CryptographyServiceAlgorithm algorithm, string password)
		{
			using (MemoryStream ms = new MemoryStream())
			{
				using (ICryptoTransform encryptor = createAlgorithm(algorithm, password).CreateEncryptor())
				{
					using (CryptoStream stream = new CryptoStream(ms, encryptor, CryptoStreamMode.Write))
					{
						stream.Write(plain, 0, plain.Length);
					}
				}
				
				return ms.ToArray();
			}
		}

		/// <summary>
		/// Decrypt a cipher byte array into plain byte array.
		/// </summary>
		/// <param name="cipher">cipher byte array</param>
		/// <param name="algorithm">algorithm to decrypt</param>
		/// <param name="password">password to decrypt</param>
		/// <returns>plain byte array</returns>
		public byte[] Decrypt(byte[] cipher, CryptographyServiceAlgorithm algorithm, string password)
		{
			using (MemoryStream ms = new MemoryStream())
			{
				using (ICryptoTransform decryptor = createAlgorithm(algorithm, password).CreateDecryptor())
				{
					using (CryptoStream stream = new CryptoStream(ms, decryptor, CryptoStreamMode.Write))
					{
						stream.Write(cipher, 0, cipher.Length);
					}
				}

				return ms.ToArray();
			}
		}
		
		private static SymmetricAlgorithm createAlgorithm(CryptographyServiceAlgorithm algorithm, string password)
		{
			SymmetricAlgorithm symmetricAlgorithm = SymmetricAlgorithm.Create(algorithm.ToString());
			Rfc2898DeriveBytes deriveBytes = new Rfc2898DeriveBytes(password, mySalt, 2);
			symmetricAlgorithm.Key = deriveBytes.GetBytes(symmetricAlgorithm.KeySize / 8);
			symmetricAlgorithm.IV = deriveBytes.GetBytes(symmetricAlgorithm.IV.Length);
			return symmetricAlgorithm;
		}
	}
}
